/' Copyright (c) 2010 Scott Lembcke
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 '/

extern "C"

'' Spatial index bounding box callback function type.
'' The spatial index calls this function and passes you a pointer to an object you added
'' when it needs to get the bounding box associated with that object.
type cpSpatialIndexBBFunc as function cdecl( byval as any ptr ) as cpBB
'' Spatial index/object iterator callback function type.
type cpSpatialIndexIteratorFunc as sub cdecl( byval as any ptr, byval as any ptr )
'' Spatial query callback function type.
type cpSpatialIndexQueryFunc as sub cdecl( byval as any ptr, byval as any ptr, byval as any ptr )
'' Spatial segment query callback function type.
type cpSpatialIndexSegmentQueryFunc as function cdecl( byval as any ptr, byval as any ptr, byval as any ptr ) as cpFloat

type cpSpatialIndexClass_ as cpSpatialIndexClass
type cpSpatialIndex_ as cpSpatialIndex

type cpSpatialIndex
	as cpSpatialIndexClass_ ptr	klass
	
	as cpSpatialIndexBBFunc		bbfunc
	
	as cpSpatialIndex_ ptr		staticIndex, dynamicIndex
end type

type cpSpaceHash_ as cpSpaceHash

'' Allocate a spatial hash.
declare function cpSpaceHashAlloc ( ) as cpSpaceHash_ ptr
'' Initialize a spatial hash. 
declare function cpSpaceHashInit ( byval as cpSpaceHash_ ptr, byval as cpFloat, byval as integer, byval as cpSpatialIndexBBFunc, byval as cpSpatialIndex ptr ) as cpSpatialIndex ptr
'' Allocate and initialize a spatial hash.
declare function cpSpaceHashNew ( byval as cpFloat, byval as integer, byval as cpSpatialIndexBBFunc, byval as cpSpatialIndex ptr ) as cpSpatialIndex ptr

'' Change the cell dimensions and table size of the spatial hash to tune it.
'' The cell dimensions should roughly match the average size of your objects
'' and the table size should be ~10 larger than the number of objects inserted.
'' Some trial and error is required to find the optimum numbers for efficiency.
declare sub cpSpaceHashResize( byval as cpSpaceHash_ ptr, byval as cpFloat, byval as integer )

type cpBBTree_ as cpBBTree

'' Allocate a bounding box tree.
declare function cpBBTreeAlloc () as cpBBTree_ ptr
'' Initialize a bounding box tree.
declare function cpBBTreeInit ( byval as cpBBTree_ ptr, byval as cpSpatialIndexBBFunc, byval as cpSpatialIndex ptr ) as cpSpatialIndex ptr
'' Allocate and initialize a bounding box tree.
declare function cpBBTreeNew ( byval as cpSpatialIndexBBFunc, byval as cpSpatialIndex ptr ) as cpSpatialIndex ptr

'' Perform a static top down optimization of the tree.
declare sub cpBBTreeOptimize ( byval as cpSpatialIndex ptr )

'' Bounding box tree velocity callback function.
'' This function should return an estimate for the object's velocity.
type cpBBTreeVelocityFunc as function cdecl( byval as any ptr ) as cpVect
'' Set the velocity function for the bounding box tree to enable temporal coherence.
declare sub cpBBTreeSetVelocityFunc( byval as cpSpatialIndex ptr, byval as cpBBTreeVelocityFunc )

type cpSweep1D_ as cpSweep1D

'' Allocate a 1D sort and sweep broadphase.
declare function cpSweep1DAlloc () as cpSweep1D_ ptr
'' Initialize a 1D sort and sweep broadphase.
declare function cpSweep1DInit ( byval as cpSweep1D_ ptr, byval as cpSpatialIndexBBFunc, byval as cpSpatialIndex ptr ) as cpSpatialIndex ptr
'' Allocate and initialize a 1D sort and sweep broadphase.
declare function cpSweep1DNew ( byval as cpSpatialIndexBBFunc, byval as cpSpatialIndex ptr ) as cpSpatialIndex ptr

type cpSpatialIndexDestroyImpL as sub cdecl( byval as cpSpatialIndex ptr )

type cpSpatialIndexCountImpl as function cdecl( byval as cpSpatialIndex ptr ) as integer
type cpSpatialIndexEachImpl as sub cdecl( byval as cpSpatialIndex ptr, byval as cpSpatialIndexIteratorFunc, byval as any ptr )

type cpSpatialIndexContainsImpl as function cdecl( byval as cpSpatialIndex ptr, byval as any ptr, byval as cpHashValue ) as cpBool
type cpSpatialIndexInsertImpl as sub cdecl( byval as cpSpatialIndex ptr, byval as any ptr, byval as cpHashValue )
type cpSpatialIndexRemoveImpl as sub cdecl( byval as cpSpatialIndex ptr, byval as any ptr, byval as cpHashValue )

type cpSpatialIndexReindexImpl as sub cdecl( byval as cpSpatialIndex ptr )
type cpSpatialIndexReindexObjectImpl as sub cdecl( byval as cpSpatialIndex ptr, byval as any ptr, byval as cpHashValue )
type cpSpatialIndexReindexQueryImpl as sub cdecl( byval as cpSpatialIndex ptr, byval as cpSpatialIndexQueryFunc, byval as any ptr )

type cpSpatialIndexPointQueryImpl as sub cdecl( byval as cpSpatialIndex ptr, byval as cpVect, byval as cpSpatialIndexQueryFunc, byval as any ptr )
type cpSpatialIndexSegmentQueryImpl as sub cdecl( byval as cpSpatialIndex ptr, byval as any ptr, byval as cpVect, byval as cpVect, byval as cpFloat, byval as cpSpatialIndexSegmentQueryFunc, byval as any ptr )
type cpSpatialIndexQueryImpl as sub cdecl( byval as cpSpatialIndex ptr, byval as any ptr, byval as cpBB, byval as cpSpatialIndexQueryFunc, byval as any ptr )

type cpSpatialIndexClass
	as cpSpatialIndexDestroyImpl destroy
	
	as cpSpatialIndexCountImpl count
	as cpSpatialIndexEachImpl each
	
	as cpSpatialIndexContainsImpl contains
	as cpSpatialIndexInsertImpl insert
	as cpSpatialIndexRemoveImpl remove
	
	as cpSpatialIndexReindexImpl reindex
	as cpSpatialIndexReindexObjectImpl reindexObject
	as cpSpatialIndexReindexQueryImpl reindexQuery
	
	as cpSpatialIndexPointQueryImpl pointQuery
	as cpSpatialIndexSegmentQueryImpl segmentQuery
	as cpSpatialIndexQueryImpl query
end type

'' Destroy and free a spatial index.
declare sub cpSpatialIndexFree ( byval as cpSpatialIndex ptr )
'' Collide the objects in @c dynamicIndex against the objects in @c staticIndex using the query callback function.
declare sub cpSpatialIndexCollideStatic ( byval as cpSpatialIndex ptr, byval as cpSpatialIndex ptr, byval as cpSpatialIndexQueryFunc, byval as any ptr )

'' Destroy a spatial index.
sub cpSpatialIndexDestroy cdecl( byval index as cpSpatialIndex ptr )
	if index->klass then index->klass->destroy( index )
end sub

'' Get the number of objects in the spatial index.
function cpSpatialIndexCount( byval index as cpSpatialIndex ptr ) as integer
	return index->klass->count( index )
end function

'' Iterate the objects in the spatial index. @c func will be called once for each object.
sub cpSpatialIndexEach( byval index as cpSpatialIndex ptr, byval func as cpSpatialIndexIteratorFunc, byval udata as any ptr )
	index->klass->each( index, func, udata )
end sub

'' Returns true if the spatial index contains the given object.
'' Most spatial indexes use hashed storage, so you must provide a hash value too.
function cpSpatialIndexContains cdecl( byval index as cpSpatialIndex ptr, byval obj as any ptr, byval hashid as cpHashValue ) as cpBool
	return index->klass->contains( index, obj, hashid )
end function

'' Add an object to a spatial index.
'' Most spatial indexes use hashed storage, so you must provide a hash value too.
sub cpSpatialIndexInsert cdecl( byval index as cpSpatialIndex ptr, byval obj as any ptr, byval hashid as cpHashValue )
	index->klass->insert( index, obj, hashid )
end sub

'' Remove an object from a spatial index.
'' Most spatial indexes use hashed storage, so you must provide a hash value too.
sub cpSpatialIndexRemove cdecl( byval index as cpSpatialIndex ptr, byval obj as any ptr, byval hashid as cpHashValue )
	index->klass->remove( index, obj, hashid )
end sub

'' Perform a full reindex of a spatial index.
sub cpSpatialIndexReindex cdecl( byval index as cpSpatialIndex ptr )
	index->klass->reindex( index )
end sub

'' Reindex a single object in the spatial index.
sub cpSpatialIndexReindexObject cdecl( byval index as cpSpatialIndex ptr, byval obj as any ptr, byval hashid as cpHashValue )
	index->klass->reindexObject( index, obj, hashid )
end sub

'' Perform a point query against the spatial index, calling @c func for each potential match.
'' A pointer to the point will be passed as @c obj1 of @c func.
sub cpSpatialIndexPointQuery cdecl( byval index as cpSpatialIndex ptr, byval p as cpVect, byval func as cpSpatialIndexQueryFunc, byval udata as any ptr )
	index->klass->pointQuery( index, p, func, udata )
end sub

'' Perform a segment query against the spatial index, calling @c func for each potential match.
sub cpSpatialIndexSegmentQuery cdecl( byval index as cpSpatialIndex ptr, byval obj as any ptr, byval a as cpVect, byval b as cpVect, byval t_exit as cpFloat, byval func as cpSpatialIndexSegmentQueryFunc, byval udata as any ptr )
	index->klass->segmentQuery( index, obj, a, b, t_exit, func, udata )
end sub

'' Perform a rectangle query against the spatial index, calling @c func for each potential match.
sub cpSpatialIndexQuery( byval index as cpSpatialIndex ptr, byval obj as any ptr, byval bb as cpBB, byval func as cpSpatialIndexQueryFunc, byval udata as any ptr )
	index->klass->query( index, obj, bb, func, udata )
end sub

'' Simultaneously reindex and find all colliding objects.
'' @c func will be called once for each potentially overlapping pair of objects found.
'' If the spatial index was initialized with a static index, it will collide it's objects against that as well.
sub cpSpatialIndexReindexQuery( byval index as cpSpatialIndex ptr, byval func as cpSpatialIndexQueryFunc, byval udata as any ptr )
	index->klass->reindexQuery( index, func, udata )
end sub

end extern
